package com.suse.warmstill.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.suse.warmstill.common.enums.RedisEnum;
import com.suse.warmstill.common.model.ArticleCondition;
import com.suse.warmstill.common.model.CallResult;
import com.suse.warmstill.common.model.ListPageModel;
import com.suse.warmstill.common.utils.RedisCache;
import com.suse.warmstill.common.utils.UserIdThreadLocal;
import com.suse.warmstill.entity.TbArticle;
import com.suse.warmstill.entity.TbArticleBody;
import com.suse.warmstill.entity.TbArticleCategory;
import com.suse.warmstill.mapper.TbArticleBodyMapper;
import com.suse.warmstill.mapper.TbArticleCategoryMapper;
import com.suse.warmstill.mapper.TbArticleMapper;
import com.suse.warmstill.mapper.TbCategoryMapper;
import com.suse.warmstill.service.ArticleService;
import com.suse.warmstill.service.BaseService;
import com.suse.warmstill.service.CosService;
import com.suse.warmstill.vo.ArticlePostVo;
import com.suse.warmstill.vo.ArticleUVo;
import com.suse.warmstill.vo.ArticleVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.webresources.Cache;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * @author 黄靖
 * @author 2022-11-02 10:33
 * description:
 **/
@Service
@Slf4j
public class ArticleServiceImpl implements ArticleService, BaseService<ArticleVo, TbArticle> {
    @Resource
    private TbArticleMapper articleMapper;

    @Resource
    private TbCategoryMapper categoryMapper;

    @Resource
    TbArticleBodyMapper articleBodyMapper;

    @Resource
    private TbArticleCategoryMapper articleCategoryMapper;

    @Resource
    private RedisTemplate<String, Integer> redisTemplate;

    @Resource
    private RedisTemplate<String,String> stringRedisTemplate;

    @Resource
    private CosService cosService;

    @Override
    public ListPageModel<ArticleVo> lists(ArticleCondition condition) {
        Page<TbArticle> articlePage = new Page<>(condition.getCurrent(), condition.getSize());

        final LambdaQueryWrapper<TbArticle> articleWrapper = new LambdaQueryWrapper<>();


        //分类
        articleWrapper.eq(TbArticle::getLittleCategoryId, condition.getCategory_id());

        //时间排序
        if (ObjectUtils.isNotEmpty(condition.getOrderByTime())) {
            if (condition.getOrderByTime() == 0) {
                /*
                 * 时间先后 降序
                 * */

                articleWrapper.orderByDesc(TbArticle::getCreateTime);
            } else {
                articleWrapper.orderByAsc(TbArticle::getCreateTime);
            }
        }
        //模糊匹配
        if (ObjectUtils.isNotEmpty(condition.getTitle())) {
            articleWrapper.like(TbArticle::getTitle, condition.getTitle());
        }

        //筛选空数据


        Page<TbArticle> page = articleMapper.selectPage(articlePage, articleWrapper);

        ListPageModel<ArticleVo> pageModel = new ListPageModel<>();
        pageModel.setPageSize(pageModel.getPageSize());
        pageModel.setCurrentPage((int) page.getCurrent());
        pageModel.setPageCount((int) page.getPages());
        pageModel.setDataSize((int) page.getTotal());


        List<TbArticle> records = page.getRecords();
        if (CollectionUtil.isEmpty(records)) {
            return pageModel;
        } else {
            ArrayList<ArticleVo> articleVos = new ArrayList<>();

            records.stream().forEach((article) -> {

                ArticleVo articleVo = new ArticleVo();

                //装配 article 表
                final CompletableFuture<Void> future0 = CompletableFuture.runAsync(() -> {
                    BeanUtils.copyProperties(toVo(article), articleVo);
                });

                //装配 点赞和 浏览量
                CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
                    articleVo.setPraiseCounts(praise(article.getId(), 2));
                    articleVo.setViewCounts(getView(article.getId()));
                });

                CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
                    //装配 category 表
                    log.info("article id =>{}", article.getId());
                    final LambdaQueryWrapper<TbArticleCategory> articlCategoryWrapper = new LambdaQueryWrapper<>();
                    articlCategoryWrapper.eq(TbArticleCategory::getArticleId, article.getId());
                    long categoryId = articleCategoryMapper.selectOne(articlCategoryWrapper).getCategoryId();
                    final String categoryName = categoryMapper.selectById(categoryId).getCategoryName();
                    articleVo.setCategory(categoryName);
                });

                CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
                    //装配 articleBody表
                    final LambdaQueryWrapper<TbArticleBody> bodyWrapper = new LambdaQueryWrapper<>();
                    bodyWrapper.eq(TbArticleBody::getArticleId, article.getBodyId());
                    final String contentHtml = articleBodyMapper.selectOne(bodyWrapper).getContentHtml();

                    articleVo.setArticleBody(contentHtml);
                });

                CompletableFuture.allOf(future0, future1, future2, future3).join();

                articleVos.add(articleVo);
            });


            pageModel.setList(articleVos);


            return pageModel;
        }
    }

    /*
     * 根据id查询
     * */
    @Override
    public ArticleVo articldetail(Long id) {
        final LambdaQueryWrapper<TbArticleBody> bodyWrapper = new LambdaQueryWrapper<>();
        final LambdaQueryWrapper<TbArticleCategory> articlCategoryWrapper = new LambdaQueryWrapper<>();
        final TbArticle article = articleMapper.selectById(id);


        ArticleVo articleVo = new ArticleVo();

        //装配 article 表
        final CompletableFuture<Void> future0 = CompletableFuture.runAsync(() -> {
            BeanUtils.copyProperties(toVo(article), articleVo);
        });

        //装配 点赞和 浏览量
        CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
            articleVo.setPraiseCounts(praise(id, 2));
            articleVo.setViewCounts(getView(id));
        });

        CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
            //装配 category 表
            articlCategoryWrapper.eq(TbArticleCategory::getArticleId, id);
            long categoryId = articleCategoryMapper.selectOne(articlCategoryWrapper).getCategoryId();
            final String categoryName = categoryMapper.selectById(categoryId).getCategoryName();
            articleVo.setCategory(categoryName);
        });

        CompletableFuture<Void> future3 = CompletableFuture.runAsync(() -> {
            //装配 articleBody表
            bodyWrapper.eq(TbArticleBody::getArticleId, article.getBodyId());
            final String contentHtml = articleBodyMapper.selectOne(bodyWrapper).getContentHtml();

            articleVo.setArticleBody(contentHtml);
        });

        CompletableFuture.allOf(future0, future1, future2, future3).join();


        return articleVo;
    }

    /*
     * 点赞方案
     * 点赞后，一段时间后 从redis中 备份到数据库
     *
     * */
    @Override
    public synchronized Long praise(Long articleId, int status) {




        String redisKey = RedisEnum.PRAISE_KEY + articleId;
        Long praiseCount = null;

        if (!redisTemplate.hasKey(redisKey)) {
            synchronized (ArticleServiceImpl.class) {
                if (!redisTemplate.hasKey(redisKey)) {
                    final Integer praiseCounts = Integer.valueOf(articleMapper.selectById(articleId).getPraiseCounts());
                    redisTemplate.opsForValue().set(redisKey, praiseCounts);
                }

            }
        }
        final Integer count = redisTemplate.opsForValue().get(redisKey);
        praiseCount = Long.valueOf(count);

        if(count != 0){
            switch (status) {
                case 0:
                    praiseCount = Long.valueOf(redisTemplate.opsForValue().increment(redisKey));
                    break;
                case 1:
                    praiseCount = Long.valueOf(redisTemplate.opsForValue().decrement(redisKey));
                    break;
                case 2:
                    praiseCount = Long.valueOf(redisTemplate.opsForValue().get(redisKey));

            }
        }
        else {
            return praiseCount;
        }


        //userid
        final Long userId = UserIdThreadLocal.get();

        String praiseKey =RedisEnum.PRAISE + userId;

        if(redisTemplate.hasKey(praiseKey)){
         String list =   stringRedisTemplate.opsForValue().get(praiseKey);
         //转化为 数组
            final List<List> lists = JSON.parseArray(list, List.class);
            if(status == 3){
                if(lists.contains(articleId)){

                }

            }
        }


        return praiseCount;
    }

    /*
     * 浏览量方案
     * */

    @Override
    public Long addViewAccount(Long articleId) {
        String redisKey = RedisEnum.VIEW_KEY + articleId;

        if (!redisTemplate.hasKey(redisKey)) {
            synchronized (ArticleServiceImpl.class) {
                if (!redisTemplate.hasKey(redisKey)) {
                    final Integer praiseCounts = Integer.valueOf(articleMapper.selectById(articleId).getViewCounts());
                    redisTemplate.opsForValue().set(redisKey, praiseCounts);

                }
            }
        }
        Long increment = redisTemplate.opsForValue().increment(redisKey);
        return increment;
    }

    /*
     * 获取浏览量
     * */
    @Override
    public Long getView(Long articleId) {
        String redisKey = RedisEnum.VIEW_KEY + articleId;

        if (!redisTemplate.hasKey(redisKey)) {
            synchronized (ArticleServiceImpl.class) {
                if (!redisTemplate.hasKey(redisKey)) {
                    final Integer praiseCounts = Integer.valueOf(articleMapper.selectById(articleId).getViewCounts());
                    redisTemplate.opsForValue().set(redisKey, praiseCounts);
                }
            }
        }

        return Long.valueOf(redisTemplate.opsForValue().get(redisKey));
    }

    @Override
    public ArticleVo toVo(TbArticle entity) {
        ArticleVo articleVo = new ArticleVo();
        articleVo.setBackgrund(entity.getBackgrund());
        articleVo.setArticleBody(entity.getAuthorName());
        articleVo.setAuthorName(entity.getAuthorName());
        articleVo.setCreateTime(entity.getCreateTime());
        articleVo.setId(entity.getId());
        articleVo.setSummary(entity.getSummary());
        articleVo.setTitle(entity.getTitle());


        return articleVo;
    }


    /*
     * 发布文章
     * */
    @Override
    public void publishArticle(ArticlePostVo article) {

        /*
         * 组装文章表
         *
         * */

        TbArticle tbArticle = new TbArticle();
        tbArticle.setAuthorName(article.getAuthorName());
        tbArticle.setPraiseCounts("30");
        tbArticle.setBackgrund(article.getBackgrundAdress());
        log.info("传来的 数据==============>{}",article);
        tbArticle.setImg(article.getImgFileAdress());
        tbArticle.setViewCounts("40");
        tbArticle.setSummary(article.getSummary());
        tbArticle.setTitle(article.getTitle());
        tbArticle.setBigCategoryId(0L);
        tbArticle.setAuthorName(article.getAuthorName());
        tbArticle.setBodyId(999L);
        tbArticle.setLittleCategoryId(article.getLittleCategoryId());

        articleMapper.insert(tbArticle);
        /*
         * 组装 文章body表
         * */

        TbArticleBody tbArticleBody = new TbArticleBody();
        tbArticleBody.setContent(article.getArticleBody().getContent());
        tbArticleBody.setContentHtml(article.getArticleBody().getContentHtml());
        tbArticleBody.setArticleId(tbArticle.getId());
        articleBodyMapper.insert(tbArticleBody);

        /*
         * 插入 articlecatory表
         * */
        final TbArticleCategory category = new TbArticleCategory();
        category.setCategoryId(article.getLittleCategoryId());
        category.setArticleId(tbArticle.getId());
        articleCategoryMapper.insert(category);

        /*
        * 重新插入body表
        * */
        final Long id = tbArticleBody.getId();
        tbArticle.setBodyId(id);
        articleMapper.updateById(tbArticle);

    }

    @Override
    public int withDraw(Long articleId) {

        articleBodyMapper.delete(new LambdaQueryWrapper<TbArticleBody>().eq(TbArticleBody::getArticleId, articleId));
        articleCategoryMapper.delete(new LambdaQueryWrapper<TbArticleCategory>().eq(TbArticleCategory::getArticleId, articleId));

        return articleMapper.delete(new LambdaQueryWrapper<TbArticle>().eq(TbArticle::getId, articleId));

    }


    @Override
    public void updateArticle(ArticleUVo article) {
        TbArticle tbArticle = new TbArticle();

        tbArticle.setAuthorName(article.getAuthorName());

        tbArticle.setSummary(article.getSummary());
        tbArticle.setTitle(article.getTitle());
        tbArticle.setId(article.getId());
        tbArticle.setAuthorName(article.getAuthorName());
        tbArticle.setLittleCategoryId(article.getLittleCategoryId());


        articleMapper.updateById(tbArticle);


        TbArticleBody tbArticleBody = new TbArticleBody();
        tbArticleBody.setContent(article.getArticleBody().getContent());
        tbArticleBody.setContentHtml(article.getArticleBody().getContentHtml());
        tbArticleBody.setArticleId(tbArticle.getId());

        articleBodyMapper.update(tbArticleBody, new LambdaQueryWrapper<TbArticleBody>().eq(TbArticleBody::getArticleId, article.getId()));

        final TbArticleCategory category = new TbArticleCategory();
        category.setArticleId(article.getId());
        category.setCategoryId(article.getLittleCategoryId());
        articleCategoryMapper.update(category, new LambdaQueryWrapper<TbArticleCategory>().eq(TbArticleCategory::getArticleId, article.getId()));


    }

    @Override
    public CallResult deleteArticle(Integer articleId) {
        return CallResult.success( articleBodyMapper.deleteById(articleId) );

    }
}
